from sqlalchemy import create_engine

engine = create_engine('sqlite:///devdt.db', echo=True)

from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.orm import mapper
from sqlalchemy.orm import relation, backref

metadata = MetaData()


from sqlalchemy import Table, Column, Integer, String, Boolean, MetaData, ForeignKey, Text
from sqlalchemy.orm import mapper
from sqlalchemy.orm import relation, backref

from crv.model import DeclarativeBase, metadata, DBSession

"""
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Cluster
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
tbCluster=Table('Cluster',metadata,
                Column('Cluster_ID',Integer,primary_key=True),
                Column('name',String, nullable=False),
                Column('currentSC',Integer,nullable=False),
                Column('targetSC',Integer,nullable=False),
                Column('statusmsg',String,nullable=True)
                )

class Cluster(object):
    class SC:
        nSC=6
        (SC_INITIALIZED,
         SC_STARTING,
         SC_RUNNING,
         SC_STOPPING,
         SC_FIXING,
         SC_EXCEPTION)=range(nSC)
        SC_STARTED=SC_RUNNING
        SC_STOPPED=SC_INITIALIZED
        canTarget=[SC_INITIALIZED,SC_RUNNING, SC_EXCEPTION]
        
    def __init__(self,vname="DummyCluster"):
#        super(Cluster, self).__init__(vname,self.SC.SC_INITIALIZED,self.SC.SC_STOPPED)
        Cluster.SCname={}
        for i in Cluster.SC.__dict__.keys():
            if i.find('SC_')>=0:
                Cluster.SCname[Cluster.SC.__dict__[i]]=i
        self.name=vname
        self.currentSC=Cluster.SC.SC_INITIALIZED
        self.targetSC=Cluster.SC.SC_INITIALIZED
        self.statusmsg=""

    def __repr__(self):
        return "Cluster(name=%s,role=(%s),attr=(%s))" % (self.name,
                                                       ",".join(map(lambda x: x.name, self.role)),
                                                       ",".join(map(lambda x: x.name, self.attr))
                                                       )

"""
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Defile RoleDef and its self-referring many-many mapping
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbRoleDef=Table('RoleDef',metadata,
                Column('RoleDef_ID',Integer,primary_key=True),
                Column('name',String,nullable=False),
                Column('doc',String,nullable=True),
                Column('mapping',String,nullable=False)                
                )

tbRoleDefDep=Table('RoleDefDep',metadata,
          Column('RoleDef_Receiver',Integer,ForeignKey('RoleDef.RoleDef_ID')),
          Column('RoleDef_Provider',Integer,ForeignKey('RoleDef.RoleDef_ID'))
          )

class RoleDef(object):
    def __init__(self,myname="",mydoc="",mymapping=""):
        self.name=myname
        self.doc=mydoc
        self.mapping=mymapping

         
    def __repr__(self):
        return "RoleDef(name=%s,doc=%s,mapping=%s,dependon=(%s))" % (self.name,self.doc,self.mapping,
                                                                     ",".join(map(lambda x: x.name, self.dependOn)))

#RoleDef self-refer many-many
mapper(RoleDef,tbRoleDef,properties={
    'dependOn':relation(RoleDef,secondary=tbRoleDefDep,primaryjoin=tbRoleDef.c.RoleDef_ID==tbRoleDefDep.c.RoleDef_Receiver,secondaryjoin=tbRoleDefDep.c.RoleDef_Provider==tbRoleDef.c.RoleDef_ID),
    })

"""
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Base class for Cluster, VM and Role
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class RunnableObj(object):
    def __init__(self,name,currentSC,targetSC,statusmsg=""):
        self.name=name
        self.currentSC=currentSC
        self.targetSC=targetSC
        self.statusmsg=statusmsg

class AttrObj(object):
    def __init__(self,aname,avalue):
        self.name=aname
        self.value=avalue
"""

"""
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# VM
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
tbVM=Table('VM',metadata,
           Column('VM_ID',Integer,primary_key=True),
           Column('name',String,nullable=False),
           Column('currentSC',Integer,nullable=False),
           Column('targetSC',Integer,nullable=False),
           Column('statusmsg',String,nullable=True),
           Column('vmtype',String,nullable=False),
           Column('identifier',String,nullable=True)
           )

class VM(RunnableObj):
    class SC:
        nSC=8
        (SC_INITIALIZED,
         SC_STARTING,
         SC_STARTING_WAIT,
         SC_RUNNING,
         SC_STOPPING_WAIT,
         SC_STOPPING,
         SC_FIXING,
         SC_EXCEPTION)=range(nSC)
        SC_STARTED=SC_RUNNING
        SC_STOPPED=SC_INITIALIZED
        canTarget=[SC_INITIALIZED,SC_RUNNING, SC_EXCEPTION]
        
    def __init__(self,vname="DummyVM",vmtype="dummy"):
        super(VM, self).__init__(vname,self.SC.SC_INITIALIZED,self.SC.SC_STOPPED)
        VM.SCname={}
        for i in VM.SC.__dict__.keys():
            if i.find('SC_')>=0:
                VM.SCname[VM.SC.__dict__[i]]=i

    def isRunning(self):
        log.debug("VM:isRunning:statuscode=%s, StatusCode.RUNNING=%s"%(str(self.statuscode),str(StatusCode.RUNNING)))
        if self.statuscode==StatusCode.RUNNING:
            return True
        return False


    def __repr__(self):
        return "VM(name=%s,role=(%s),attr=(%s))" % (self.name,
                                                    ",".join(map(lambda x: x.name, self.role)),
                                                    ",".join(map(lambda x: x.name, self.attr)),
                                                    )            
"""
        
"""
    
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Create Role and its self-referring many-many mapping
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbRole=Table('Role',metadata,
             Column('Role_ID',Integer,primary_key=True),
             Column('RoleDef_ID',Integer,ForeignKey('RoleDef.RoleDef_ID')),
             Column('VM_ID',Integer,ForeignKey('VM.VM_ID')),             
             Column('name',String,nullable=False),
             Column('currentSC',Integer,nullable=False),
             Column('targetSC',Integer,nullable=False),
             Column('statusmsg',String,nullable=True),
             Column('enabled',Boolean,nullable=False)           
             )

tbRoleDep=Table('RoleDep',metadata,
          Column('Role_Receiver',Integer,ForeignKey('Role.Role_ID')),
          Column('Role_Provider',Integer,ForeignKey('Role.Role_ID'))
          )

class Role(object):
    class SC:
        nSC=6
        (SC_INITIALIZED,
         SC_APPLYING,
         SC_RUNNING,
         SC_REMOVING,
         SC_FIXING,
         SC_EXCEPTION)=range(nSC)
        SC_STARTED=SC_RUNNING
        SC_STOPPED=SC_INITIALIZED
        canTarget=[SC_INITIALIZED,SC_RUNNING, SC_EXCEPTION]
        
    def __init__(self,vname="DummyRole"):
#        super(Role, self).__init__(vname,self.SC.SC_INITIALIZED,self.SC.SC_STOPPED)
        self.enabled=True
        Role.SCname={}
        for i in Role.SC.__dict__.keys():
            if i.find('SC_')>=0:
                Role.SCname[Role.SC.__dict__[i]]=i
        self.name=vname
        self.currentSC=Role.SC.SC_INITIALIZED
        self.targetSC=Role.SC.SC_INITIALIZED
        self.enabled=True
        self.statusmsg=""
        
    def __repr__(self):
        return "Role(name=%s,dependOn=(%s),roleDef=%s,attr=(%s),vm=%s)"%(self.name,
                                                                         ",".join(map(lambda x: x.name, self.dependOn)),
                                                                         self.roleDef.name,
                                                                         ",".join(map(lambda x: x.name, self.attr)),
                                                                         self.vm.name
                                                                         )
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# RoleAttr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbRoleAttr=Table('RoleAttr',metadata,
                 Column('RoleAttr_ID',Integer,primary_key=True),
                 Column('Role_ID',Integer,ForeignKey('Role.Role_ID')),
                 Column('name',String,nullable=False),
                 Column('value',Text)
                 )

class RoleAttr(AttrObj):
    def __repr__(self):
        return "RoleAttr(name=%s,value=%s,role=%s)" % (self.name,self.value,self.role.name)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# VMAttr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
tbVMAttr=Table('VMAttr',metadata,
                 Column('VMAttr_ID',Integer,primary_key=True),
#                 Column('VM_ID',Integer,ForeignKey('VM.VM_ID')),
                 Column('name',String,nullable=False),
                 Column('value',Text)
                 )

class VMAttr(AttrObj):
    def __repr__(self):
        return "VMAttr(name=%s,value=%s,vm=%s)" % (self.name,self.value,self.vm.name)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ClusterAttr
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbClusterAttr=Table('ClusterAttr',metadata,
                 Column('ClusterAttr_ID',Integer,primary_key=True),
                 Column('Cluster_ID',Integer,ForeignKey('Cluster.Cluster_ID')),
                 Column('name',String,nullable=False),
                 Column('value',Text)
                 )

class ClusterAttr(AttrObj):
    def __repr__(self):
        return "ClusterAttr(name=%s,value=%s,cluster=%s)" % (self.name, self.value, self.cluster.name)


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# table for n-m mapping of Cluster-Role
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
tbClusterRole = Table('ClusterRole', metadata,
                      Column('Cluster_ID', Integer, ForeignKey('Cluster.Cluster_ID'), primary_key = True),
                      Column('Role_ID', Integer, ForeignKey('Role.Role_ID'), primary_key = True))                      
"""

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Mapping of things
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
"""

#Cluster
#  1 cluster - many ClusterAttr
mapper(Cluster,tbCluster,
       properties={
#    'attr':relation(ClusterAttr,backref='cluster'),    
    })

#VM
# 1 VM - Many VMAttr
mapper(VM,tbVM,
       properties={
#    'attr':relation(VMAttr,backref='vm'),    
    })
"""

"""
#Role, mappings:
#  (many Role - many Role)
#  (1 Role - many RoleAttr)
#  (Many Role - 1 VM)
#  (Many Role - Many Cluster)
#  (many Role - 1 RoleDef )
mapper(Role,tbRole,
       properties={
    'dependOn':relation(Role,secondary=tbRoleDep,primaryjoin=tbRole.c.Role_ID==tbRoleDep.c.Role_Receiver,secondaryjoin=tbRoleDep.c.Role_Provider==tbRole.c.Role_ID,backref='dependBy'),
    'roleDef':relation(RoleDef), #No backref since we don't need to know what Roles a RoleDef has
    'vm':relation(VM,backref='role'),
    'cluster':relation(Cluster,secondary=tbClusterRole,backref='role'),   
    'attr':relation(RoleAttr,backref='role'),
    })

#RoleAttr
mapper(RoleAttr,tbRoleAttr)
#VMAttr
#mapper(VMAttr,tbVMAttr)
#ClusterAttr
mapper(ClusterAttr,tbClusterAttr)
            

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# The Lock table and class
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
tbLock=Table('Lock',metadata,
             Column('name',String,primary_key=True,nullable=False),
             )

class Lock(object):
    def __init__(self,name):
        self.name=name
        
    def __repr__(self):
        return "Lock(name=%s)" % (self.name)

mapper(Lock,tbLock)

class NamedLock(object):
    def __init__(self,name,wait=1):
        self.name=name
        self.wait=wait
        self.lock=None
        
    def __enter__(self):
        while True:
            #Query the database to see if a record with the same name exists
            log.debug("NamedLock::__enter__  name=%s, querying"%(self.name))
            locks = DBSession.query(Lock).filter_by(name=self.name).all()
            log.debug("NamedLock::__enter__  len(locks)=%d"%(len(locks)))
            
            if len(locks)<1:
                log.debug("NamedLock::__enter__  adding lock name=%s"%(self.name))

                #no lock exist, lock it and exit
                self.lock=Lock(self.name)
                DBSession.add(self.lock)
                transaction.commit()
                log.debug("NamedLock::__enter__ committed")
                break
            else:
                #exist lock so we wait
                log.debug("NamedLock::Lock exist for name=%s, waiting..."%(self.name))
                time.sleep(self.wait)
        return None
    
    def __exit__(self, type, value, traceback):
        log.debug("NamedLock::__exit__ called, type=%s, value=%s, traceback=%s"%(str(type),str(value),str(traceback)))
        
        #we release the lock
        DBSession.delete(self.lock)
        transaction.commit()

        if type!=None or value!=None or traceback!=None:
            #something wrong, so return false to let python raise the exception
            log.debug("NamedLock::__exit__ returning False")
            return False
        
        return True
"""

metadata.create_all(engine)

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()


    #Role Definitions
rdProxy=RoleDef('Proxy',"Proxy Server","profileProxy")
rdHead=RoleDef('Head',"Condor Head","profileHead")
rdWorker=RoleDef('Worker',"Condor Worker","profileWorker")
    
rdWorker.dependOn.append(rdHead)
    #rdWorker.dependOn.append(rdProxy)
    #rdHead.dependOn.append(rdProxy)

session.add(rdProxy)
session.add(rdHead)
session.add(rdWorker)
"""

    #Roles - i.e. realized role definitions
    rProxy=Role('rProxy')
    rProxy.roleDef=rdProxy
    
    rHead=Role('rHead')
    rHead.roleDef=rdHead

    rWorker1=Role('rWorker1')
    rWorker1.roleDef=rdWorker
    
    rWorker2=Role('rWorker2')
    rWorker2.roleDef=rdWorker
    
    #crvtools.buildRoleDep([rProxy,rHead,rWorker1,rWorker2])
    
    session.add(rProxy)
    session.add(rHead)
    session.add(rWorker1)
    session.add(rWorker2)
    rProxy.attr.append(RoleAttr("RefreshInterval","5"))
    rHead.attr.append(RoleAttr("MaxWorker","10"))
    rWorker1.attr.append(RoleAttr("MaxLoad","Big"))
    rWorker2.attr.append(RoleAttr("MaxLoad","Small"))
    
    vm0=VM("VM0")
#    vm0.attr.append(VMAttr("IP","10.0.0.1"))
    vm0.vmtype="euca"
    vm0.active=True
    rProxy.vm=vm0
    rHead.vm=vm0
    
    vm1=VM("VM1")
#    vm1.attr.append(VMAttr("IP","10.0.0.10"))
    vm1.vmtype="euca"
    vm1.active=True
    rWorker1.vm=vm1
    
    vm2=VM("VM2")
#    vm2.attr.append(VMAttr("IP","10.0.0.11"))
    vm2.vmtype="euca"
    vm2.active=True
    rWorker2.vm=vm2
"""
#cl=Cluster("tier3")
#    cl.role.append(rProxy)
#    cl.role.append(rHead)
#    cl.role.append(rWorker1)
#    cl.role.append(rWorker2)    
 #   cl.active=True
#session.add(cl)


session.commit()

          
